"-----------------------------------------------------------------------------
"- default options
"-----------------------------------------------------------------------------
syntax enable
filetype plugin indent on

" Leader key
let mapleader=' '
let g:mapleader=' '

" Enable build-in manpage viewer
runtime ftplugin/man.vim

" Enable some build-in plugins
packadd comment
packadd hlyank

" for tmux version < 3.4
" if exists("$TMUX")
"   let &t_RB = "\ePtmux;\e\e]11;?\007\e\\"
" endif
" for tmux version >= 3.4
if exists("$TMUX")
  let &t_RB = "\e]11;?\007"
endif

" Fix bug when enable true color for vim
let &t_8f = "\<Esc>[38:2:%lu:%lu:%lum"
let &t_8b = "\<Esc>[48:2:%lu:%lu:%lum"

" Change cursor shape to bar in insert mode
if !has("gui_running")
  let &t_EI = "\e[2 q"   " normal mode
  let &t_SI = "\e[6 q"   " insert mode
  let &t_SR = "\e[4 q"   " replace mode
endif

set termguicolors
colorscheme retrobox
set shortmess=atcCIF
set viminfo='270,f1,<1000,:270,s100,!
if !isdirectory($HOME . "/.vim/vimswap")
    call mkdir($HOME . "/.vim/vimswap", "p", 0755)
endif
set directory=~/.vim/vimswap,/tmp
if !isdirectory($HOME . "/.vim/vimundo")
    call mkdir($HOME . "/.vim/vimundo", "p", 0755)
endif
set undodir=~/.vim/vimundo
set undofile
set hidden
set autoread
set cursorline
set number
set relativenumber
set splitbelow
set splitright
set list
set listchars=tab:›·,trail:•,precedes:«,extends:»,nbsp:%
set autochdir
set autoindent
set complete=.,w,b,u
set completeopt=menu,menuone,noselect,fuzzy,preview,popup
set completefuzzycollect=keyword,files,whole_line
set wildmenu
set wildoptions=fuzzy,pum,tagfile
set wildmode=longest,full
set wildignore=*.o,*~,*.pyc,*.class
set pumheight=27
set showmatch
set matchtime=2
set hlsearch
set incsearch
set maxsearchcount=222
set ignorecase
set smartcase
set matchpairs+=<:>
set smarttab
set showcmd
set ttimeout
set ttimeoutlen=50
set display=lastline
set sidescroll=50
set formatoptions+=mB
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,latin1
set spelloptions=camel
set spellfile=~/.vim/spell/en.utf-8.add
set dictionary+=~/.vim/spell/engspchk.dict
set thesaurus=~/.vim/thesaurus/english.txt
set statusline=%{utils_func#printMode()}\ %r%y%m\ %F%=[%L:%l,%2v]\ [%{utils_func#humanReadableSize(getfsize(expand(@%)))}]\ [%{&ff}]\ [%{(&fenc!=''?&fenc:&enc)}%{(&bomb?\\",BOM\\":\\"\\")}]\ CZ
set laststatus=2
set noshowmode
set diffopt+=linematch:60
if executable("rg")
  set grepprg=rg\ --vimgrep\ --smart-case\ -M\ 200\ --max-columns-preview\ --follow
  set grepformat^=%f:%l:%c:%m
endif

"-----------------------------------------------------------------------------
"- autocmds
"-----------------------------------------------------------------------------
" Move to exit position when open file, if this not work ,make sure .viminfo is writable for you
" see :h last-position-jump
augroup RestoreCursor
  autocmd!
  autocmd BufReadPost *
    \ let line = line("'\"")
    \ | if line >= 1 && line <= line("$") && &filetype !~# 'commit'
    \      && index(['xxd', 'gitrebase'], &filetype) == -1
    \      && !&diff
    \ |   execute "normal! g`\"zz"
    \ | endif
augroup END

augroup SaveAndMkdir
  au!
  " Auto-create parent directories (except for URIs "://").
  " see neovim :h ++p
  au BufWritePre,FileWritePre * if @% !~# '\(://\)' | call mkdir(expand('<afile>:p:h'), 'p') | endif
augroup end

" Filetype
augroup ft
  au!
  au CmdwinEnter * map <buffer> q <Cmd>quit<CR>
  au FileType help,man nnoremap <buffer> q <Cmd>quit<CR>
  au Filetype java,javascript setlocal shiftwidth=4 tabstop=4 expandtab
  au Filetype vim,lua,c,yaml,json,css setlocal shiftwidth=2 tabstop=2 expandtab
  au BufNewFile *.lua, call setline(1, ["\#!/usr/bin/env lua", "", ""]) | normal G
  au BufNewFile *.sh, call setline(1, ["\#!/usr/bin/env bash", "", ""]) | normal G
  au TerminalWinOpen * setlocal statusline=%{utils_func#printMode()}\ %F nornu

  " temporally fix the incorrectly highlight for """\"""" in python file
  " see detail on https://github.com/neovim/neovim/commit/6e233b93ea03c67b80658a964d9a1a134792a9bd
  au FileType python syn region pythonString matchgroup=pythonTripleQuotes
        \ start=+[uU]\=\z('''\|"""\)+ skip=+\\["'\\]+ end="\z1" keepend
        \ contains=pythonEscape,pythonSpaceError,pythonDoctest,@Spell
augroup end

augroup cmdlineConf
  au!
  au CmdlineEnter * :let s:save_iskeyword = &l:iskeyword | setlocal iskeyword=@,48-57,192-255,#
  au CmdlineLeave * let &l:iskeyword = s:save_iskeyword
augroup end

"-----------------------------------------------------------------------------
"- mapping
"-----------------------------------------------------------------------------

nnoremap <silent> <F7> :term<CR>
" <TAB>: completion.
inoremap <silent><expr> <TAB>
      \ pumvisible() ? "\<C-n>" :
      \ utils_func#checkBackSpace() ? "\<TAB>" : "\<C-n>"
" <S-TAB>: completion back.
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
nnoremap <space> <Nop>
nnoremap k gk
nnoremap gk k
nnoremap j gj
nnoremap gj j
noremap H ^
noremap L $
noremap <leader>j <C-W>j
noremap <leader>k <C-W>k
noremap <leader>h <C-W>h
noremap <leader>l <C-W>l
nnoremap <leader>d :bd<CR>
nnoremap <leader>e :e<Space>
nnoremap <leader>q :q<CR>
nnoremap <leader>Q :qa<CR>
nnoremap <leader>1 :q!<CR>
nnoremap <leader>2 :wq<CR>
nnoremap <leader>w :w<CR>
nnoremap <leader>x :x<CR>
nnoremap <leader>as ggVG
nnoremap U <C-r>
nnoremap Y y$
nnoremap <leader><leader> <c-^>
nnoremap <silent> <leader>o :<C-u>call append(line("."),   repeat([""], v:count1))<CR>
nnoremap <silent> <leader>O :<C-u>call append(line(".")-1, repeat([""], v:count1))<CR>
vnoremap <leader>ys "+y
nnoremap <leader>yy "+yy
nnoremap <leader>yp "+p
nnoremap <leader>yr <Cmd>reg <bar>exec 'normal! "' . input('> ') . 'p'<CR>
inoremap <C-x>r <Cmd>reg <bar>call feedkeys("\<C-r>" . input('> '), 'i')<CR>
nnoremap gp `[v`]
noremap <silent> <Leader>ll :call matchadd('PmenuSel', '\%'.line('.').'l')<CR>
nnoremap <silent> <Leader>lc :call clearmatches()<CR>
set cedit=\<C-L>
cnoremap <C-a> <Home>
cnoremap <C-f> <Right>
cnoremap <C-b> <Left>
cnoremap <C-d> <Del>
cnoremap <C-k> <C-\>e(strpart(getcmdline(), 0, getcmdpos() - 1))<CR>
silent! exe "set <F29>=\<Esc>b"
silent! exe "set <F30>=\<Esc>f"
silent! exe "set <F31>=\<Esc>d"
" cnoremap <F29> <S-Left>
" cnoremap <F30> <S-Right>
" cnoremap <F31> <S-Right><C-W>
function! s:optCmd(opt) abort
  "see https://github.com/vim/vim/issues/12623"
  "let l:pat = '\k*\%' . l:cursorPos . 'c\zs\%(\k\+\|\%(\k\@!.\)\+\)'
  let l:cursorPos = getcmdpos()
  let l:pat = '\k*\%' . l:cursorPos . 'c\zs\%(\k\+\|.\{-}\<\k\+\>\|\%(\k\@!.\)\+\)'
  let l:cmdlineInput = getcmdline()
  let l:cmdlineLen = strlen(l:cmdlineInput)
  if a:opt=="del"
    if l:cursorPos == l:cmdlineLen + 1
      return ''
    endif
    return repeat("\<Del>", strchars(matchstr(l:cmdlineInput, l:pat)))
  elseif a:opt=="forward"
    if l:cursorPos == l:cmdlineLen + 1
      return ''
    endif
    return repeat("\<Right>", strchars(matchstr(l:cmdlineInput, l:pat)))
  elseif a:opt=="back"
    if l:cursorPos == 1
      return ''
    endif
    let l:reversed_cmdlineInput = join(reverse(split(l:cmdlineInput, '\zs')), '')
    let l:pos = (l:cursorPos < l:cmdlineLen + 1)
          \ ? l:cmdlineLen - l:cursorPos + 2
          \ : 1
    let l:pat = '\k*\%' . l:pos . 'c\zs\%(\k\+\|.\{-}\<\k\+\>\|\%(\k\@!.\)\+\)'
    return repeat("\<Left>", strchars(matchstr(l:reversed_cmdlineInput, l:pat)))
  endif
endfunction
cnoremap <expr> <F29> <SID>optCmd("back")
cnoremap <expr> <F30> <SID>optCmd("forward")
cnoremap <expr> <F31> <SID>optCmd("del")
tnoremap <F29> <Esc>b
tnoremap <F30> <Esc>f
tnoremap <F31> <Esc>d
if has("gui")
  " Move in command line
  cnoremap <expr> <M-b> <SID>optCmd("back")
  cnoremap <expr> <M-f> <SID>optCmd("forward")
  cnoremap <expr> <M-d> <SID>optCmd("del")
  " Move in terminal buffer
  tnoremap <M-b> <Esc>b
  tnoremap <M-f> <Esc>f
  tnoremap <M-d> <Esc>d
endif
vnoremap J :m '>+1<CR>gv=gv
vnoremap K :m '<-2<CR>gv=gv
nnoremap <silent> <C-j> :bNext<CR>
nnoremap <silent> <C-k> :bprevious<CR>
function! BroOl()
  call filter(v:oldfiles, 'v:val !~ "COMMIT_EDITMSG"')
  call filter(v:oldfiles, 'v:val !~ "/usr/share/vim"')
  call filter(v:oldfiles, "filereadable(fnamemodify(v:val, ':p'))")
  browse :oldfiles
endfunction
" nnoremap <silent><leader>bh :call BroOl()<CR>
" nnoremap <C-e> :set nomore <Bar> :ls <Bar> :set more <CR>:b<Space>
" nnoremap <Leader>bb :ls<CR>:b<Space>
if &diff
  nnoremap <C-n> ]c
  nnoremap <C-p> [c
  nnoremap <leader>1 :qa<CR>
endif

" Maximize buffer at a single tabpage
function! ToggleTabEdit() abort
  if winnr() == 1 && tabpagenr() != 1
    let l:save_pos = getpos('.')
    let l:buf_name = buffer_name()
    tabclose
    if l:buf_name == buffer_name()
      call setpos('.', l:save_pos)
    endif
  else
    exec "tab sp|normal zz"
  endif
endfunction
nnoremap <silent><leader>m :call ToggleTabEdit()<CR>
